package com.clouddisk.dao;

import com.clouddisk.POJO.HDFSFile;
import lombok.SneakyThrows;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.text.Collator;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@Component
public class FileSystemDao {
    @Value("${hadoopPath}")
    private String hadoopPath;

    @Value("${userinfo}")
    private String userinfo;

    @SneakyThrows
    public FileSystem getFileSystem() {
        Configuration conf = new Configuration();
//        conf.set("fs.defaultFS", hadoopPath);
        conf.set("dfs.client.block.write.replace-datanode-on-failure.policy","NEVER");
        conf.set("dfs.client.block.write.replace-datanode-on-failure.enable","true");
        conf.set("dfs.client.use.datanode.hostname", "true");
//        conf.set("dfs.datanode.use.datanode.hostname", "true");
//        return FileSystem.get(conf);
        return FileSystem.get(new URI(hadoopPath), conf, "root");
    }

    public void createCheck() throws IOException {
        FileSystem fs = getFileSystem();
        if (!fs.exists(new Path(userinfo))) {
            fs.create(new Path(userinfo));
        }
    }

    // 用户登录检查(OK)
    public boolean loginCheck(String userName,String password) throws IOException {
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(userinfo);
        FSDataInputStream in = fs.open(srcPath);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        String line = "";
        while((line = reader.readLine()) != null){
            String[] userinfo = line.split(",");
            if(userinfo[0].equals(userName) && userinfo[1].equals(password)){
                // 用户名密码正确
                fs.close();
                return true;
            }
        }

        // 未找到
        fs.close();
        return false;
    }

    // 注册时，检查用户名是否已经存在(OK)
    public boolean userExistCheck(String userName) throws IOException {
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(userinfo);
        FSDataInputStream in = fs.open(srcPath);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        String line = "";
        while((line = reader.readLine()) != null){
            String[] userinfo = line.split(",");
            if(userinfo[0].equals(userName)){
                // 找到同名用户
                fs.close();
                return true;
            }
        }

        // 未找到
        fs.close();
        return false;
    }

    // 注册用户(OK)
    public void insertUserInfoToFile(String userName, String password) throws IOException {
        System.out.println("register:userName= " +userName + " , password= " + password);
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(userinfo);
        FSDataOutputStream out = fs.append(srcPath);
        String userinfo = userName+","+password+"\n";
        out.write(userinfo.getBytes(StandardCharsets.UTF_8));

        // 创建用户的同时，以用户的名字创建单独文件夹
        mdkir("/"+userName);

        out.close();
        fs.close();
    }

    // 删除用户(删除原来记录用户信息的文件，重新创建一个)
    public void deleteUserInfoFromFile(String userName) throws IOException {
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(userinfo);
        FSDataInputStream in = fs.open(srcPath);
        FSDataOutputStream out = fs.create(srcPath);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder sb = new StringBuilder();
        String line = "";

        while ((line = reader.readLine()) != null){
            String[] user = line.split(",");
            if(user[0].equals(userName)){
                continue;
            }
            sb.append(line).append("\n");
        }
        out.write(sb.toString().getBytes(StandardCharsets.UTF_8));

        in.close();
        out.close();
        fs.close();
    }

    // 检查文件或目录是否存在
    public boolean checkFileExist(String path) throws IOException {
        Path srcPath = new Path(path);
        FileSystem fs = getFileSystem();
        boolean ret = fs.exists(srcPath);
        return ret;
    }

    // 创建目录
    public void mdkir(String path) throws IOException {
        Path newPath = new Path(path);
        FileSystem fs = getFileSystem();
        fs.mkdirs(newPath);
        fs.close();
    }

    // 删除文件或目录
    public void delete(String path) throws IOException {
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(path);
        fs.delete(srcPath,true);
        fs.close();
    }

    public List<HDFSFile> getFileList(String path) throws IOException {
        Path newPath = new Path(path);
        FileSystem fs = getFileSystem();
        // 设置规格时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<HDFSFile> fileList = new ArrayList<HDFSFile>();
        FileStatus[] fileStatuses = fs.listStatus(newPath);

        for(FileStatus fileStatus:fileStatuses){
            HDFSFile file = new HDFSFile();
            // 获取文件名称
            file.setFileName(fileStatus.getPath().getName());
            // 获取文件上次修改时间
            file.setDate(dateFormat.format(fileStatus.getModificationTime()));

            if(fileStatus.isDirectory()){
                file.setFileType("directory");
            }else {
                file.setFileType("file");
            }
            fileList.add(file);
        }

        //排序，目录放前面，文件放后面
        Collator collator = Collator.getInstance(Locale.CHINA);
        fileList.sort((f1, f2) -> (collator.compare(f1.getFileType(), f2.getFileType())));
        return fileList;
    }

    public List<HDFSFile> findFile(String path,String fileName) throws IOException {
        FileSystem fs = getFileSystem();
//        FileStatus fileStatus = fs.getFileStatus();
//        fileStatus.getPath();
        List<HDFSFile> ret = new ArrayList<HDFSFile>();
        List<HDFSFile> list = getFileList(fileName);
        for(HDFSFile file:list){
            if(file.getFileName().contains(fileName)){
//                ret.add(path + "/" + fileName)
            }
        }
        return list;
    }

    // 移动文件（复制后，删除原文件）
    public void moveToElsePlace(String oldPath,String newPath) throws IOException {
        FileSystem fs = getFileSystem();
        Path oldOne = new Path(oldPath);
        Path newOne = new Path(newPath);
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS",hadoopPath);

        // 复制文件到指定路径
        FileUtil.copy(fs, oldOne, fs, newOne,true,conf);
    }

    // 更改文件名称
    public void fileRename(String oldName,String newName) throws IOException {
        FileSystem fs = getFileSystem();
        Path oldOne = new Path(oldName);
        Path newOne = new Path(newName);
        fs.rename(oldOne,newOne);
    }
    
    // 复制文件到指定位置
    public void copyToElsePlace(String oldPath,String newPath) throws IOException {
        FileSystem fs = getFileSystem();
        Path oldOne = new Path(oldPath);
        Path newOne = new Path(newPath);
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS",hadoopPath);

        // 复制文件到指定路径
        FileUtil.copy(fs, oldOne, fs, newOne,false,conf);
    }

}
